from pymongo import MongoClient, UpdateOne
from faker import Faker
import random
import string


'''
使用 Faker 库生成一个随机的中文姓名。在函数中创建了一个 Faker 对象，使用 zh_CN 语言模式生成中文姓名。
然后使用 fake.name() 方法生成一个随机的中文姓名，并将其保存到 name 变量中。
最后，将生成的中文姓名作为函数的返回值。
'''
def generate_random_chinese_name_one():
    # 创建一个 Faker 对象，使用 zh_CN 语言模式生成中文姓名
    fake = Faker('zh_CN')
    # 生成一个随机的中文姓名
    name = fake.name()
    # 返回生成的中文姓名
    return name


'''
使用 Python 内置的 random 模块生成一个随机的五位数。
在函数中，使用 random.randint(a, b) 方法生成一个指定范围内的随机整数，
范围为 10000 到 99999（包括两端）。最后将生成的随机整数作为函数的返回值。
'''
def generate_five_digit_random_number():
    # 生成一个 10000 到 99999 之间的随机整数
    return random.randint(10000, 99999)


'''
使用 Python 内置的 string 模块和 random 模块生成一个包含字母和数字的随机字符串。
在函数中，首先使用 string.ascii_letters 获取所有字母（包括大小写），使用 string.digits 获取所有数字，然后将它们合并成一个包含字母和数字的字符集 chars。
接下来，使用列表推导式生成一个长度为 5 的随机字符串 random_string，每个字符都从字符集 chars 中随机选择。
最后，将生成的随机字符串作为函数的返回值。
'''
def generate_five_digit_random_letters_string():
    # 定义包含字母和数字的字符集
    chars = string.ascii_letters + string.digits
    # 生成一个长度为 5 的随机字符串，包含字符集中的随机字符
    random_string = ''.join(random.choice(chars) for _ in range(5))
    # 返回生成的随机字符串
    return random_string


'''
用于在 MongoDB 的集合中更新指定字段的值。
在函数中，首先定义了一个 bulk_operations 列表，用于存储批量操作。
然后，定义了查询条件和投影，用于选择需要修改的文档和字段。
接着，使用 collection.find() 方法查询满足条件的文档，并遍历每个文档。
在遍历文档的过程中，首先获取需要修改的字段值，并根据该字段值生成一个新的随机字符串，用于替换原来的字符串后5位。
然后，将更新操作添加到 bulk_operations 列表中。
最后，如果有需要更新的文档，则执行 collection.bulk_write() 方法进行批量操作。
多层嵌套适用
'''
def update_token_in(collection, field):
    # 初始化 bulk 操作列表
    bulk_operations = []
    # 定义查询条件，只选择字段不为空的文档
    query = {field: {"$ne": None}}
    # 定义投影，只返回需要修改的字段
    projection = {field: 1}

    # 遍历满足条件的文档
    for document in collection.find(query, projection):
        # 获取需要修改的字段值
        old_value = document
        for key in field.split('.'):
            old_value = old_value.get(key)
            if old_value is None:
                break

        # 生成一个新的随机字符串，用于替换原来的字符串后5位
        new_token = generate_five_digit_random_letters_string()
        # 旧的token值为原始值的后5位
        old_token = old_value[-5:]
        # 使用新的随机字符串替换旧的token值
        new_field = old_value.replace(old_token, str(new_token))

        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: new_field}}
            )
        )

    # 如果有需要更新的文档，则执行 bulk 操作
    if bulk_operations:
        collection.bulk_write(bulk_operations)


'''
用于在 MongoDB 的集合中更新指定字段的值为随机生成的中文名。
在函数中，首先定义了一个 bulk_operations 列表，用于存储批量操作。
然后，定义了查询条件和投影，用于选择需要修改的文档和字段。
接着，使用 collection.find() 方法查询满足条件的文档，并遍历每个文档。
在遍历文档的过程中，首先生成一个新的随机中文名，并将更新操作添加到 bulk_operations 列表中。
然后，打印更新后的值，并在达到批量操作阈值时执行 collection.bulk_write() 方法进行批量操作。
最后，如果有剩余的 bulk 操作，则执行。
通用型
'''
def update_chinese_name(collection, field):
    # 初始化 bulk 操作列表
    bulk_operations = []
    # 定义查询条件，只选择字段不为空的文档
    query = {field: {"$ne": None}}
    # 定义投影，只返回需要修改的字段和 _id 字段
    projection = {"_id": 1, field: 1}

    # 遍历满足条件的文档
    for document in collection.find(query, projection):
        # 生成一个新的随机中文名
        new_name = generate_random_chinese_name_one()

        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: new_name}}
            )
        )

        # 打印更新后的值
        print(f"更新为 {new_name}")

        # 如果 bulk 操作列表长度为1000，则执行 bulk 操作
        if len(bulk_operations) == 1000:
            collection.bulk_write(bulk_operations)
            # 清空 bulk 操作列表
            bulk_operations = []

    # 如果有剩余的 bulk 操作，则执行
    if bulk_operations:
        collection.bulk_write(bulk_operations)


'''在MongoDB数据库中对指定的collection和field进行更新。
具体地，对于每个包含指定field的非空文档，将field的后五位替换为一个随机生成的五位数字，并将更新后的文档添加到bulk操作列表中。
当bulk操作列表的长度达到1000时，执行bulk操作。
最终，如果还有剩余的bulk操作，也会执行。
普通型
'''
def update_number(collection, field):
    # 初始化 bulk 操作列表
    bulk_operations = []
    # 定义查询条件，只选择字段不为空的文档
    query = {field: {"$ne": None}}
    # 只返回需要修改的字段
    projection = {field: 1}

    for document in collection.find(query, projection):
        # 获取需要修改的值
        old_value = document.get(field)
        # 如果值不存在，则跳过此文档
        if not old_value:
            continue
        # 生成随机数字
        new_number = generate_five_digit_random_number()
        # 修改后5位
        old_number = old_value[-5:]
        new_field = old_value.replace(old_number, str(new_number))
        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: new_field}}
            )
        )

        # 打印更新后的值
        print(f"更新 {old_value} 为 {new_field}")

    # 如果有需要更新的文档，则执行 bulk 操作
    if bulk_operations:
        collection.bulk_write(bulk_operations)


'''
在MongoDB集合中，针对指定字段中的数字进行更新。
具体来说，代码会对集合中符合条件的文档进行遍历，获取指定字段的值，并用随机生成的五位数替换掉该数字的后五位。
最后，将更新后的文档批量写入数据库。
值得注意的是，指定字段可以为嵌套的字段，代码会根据"."分割符号逐级获取该字段的值。
多层嵌套适用
'''
def update_number_in(collection, field):
    # 定义bulk操作列表
    bulk_operations = []
    # 定义查询条件
    query = {field: {"$ne": None}}
    # 只返回需要修改的字段
    projection = {field: 1}

    for document in collection.find(query, projection):
        # 获取需要修改的值，支持嵌套文档
        old_value = document
        for key in field.split('.'):
            old_value = old_value.get(key)
            if old_value is None:
                break
        # 生成随机数字
        new_number = generate_five_digit_random_number()
        # 修改后5位
        old_number = old_value[-5:]
        new_field = old_value.replace(old_number, str(new_number))
        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: new_field}}
            )
        )

        # 打印更新日志
        print(f"更新 {old_value} 为 {new_field}")

    # 如果有需要更新的文档，则执行 bulk 操作
    if bulk_operations:
        collection.bulk_write(bulk_operations)


'''
将MongoDB集合（collection）中指定字段（field）为空的文档的该字段的值设为None。
具体实现是，首先使用find()方法查询集合中所有文档的指定字段值，如果该值为空则跳过此文档，否则将该文档的指定字段的值设为None，并使用bulk_write()方法批量操作。
通用型
'''
def update_none(collection, field):
    # 定义bulk操作列表
    bulk_operations = []
    # 定义查询条件
    query = {}
    # 只返回需要修改的字段
    projection = {field: 1}

    for document in collection.find(query, projection):
        # 获取需要修改的值
        old_value = document.get(field)
        # 如果值不存在，则跳过此文档
        if not old_value:
            continue
        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: None}}
            )
        )

    # 如果有需要更新的文档，则执行 bulk 操作
    if bulk_operations:
        collection.bulk_write(bulk_operations)


'''
将 MongoDB 集合中某个字段的值设置为空列表（[]），对所有文档进行操作。
函数首先定义了一个空的查询条件和一个 projection，只返回需要修改的字段。
然后，它遍历了整个集合，获取了需要修改的字段的值。
如果该值不存在，函数跳过当前文档，否则将一个 MongoDB 更新操作添加到 bulk_operations 列表中，将该字段的值设置为空列表。
最后，如果有需要更新的文档，则执行批量更新操作。
通用型
'''
def update_none_list(collection, field):
    # 用于存储所有的更新操作
    bulk_operations = []
    # 查询条件为空，表示要更新所有文档
    query = {}
    # 只返回需要修改的字段
    projection = {field: 1}

    for document in collection.find(query, projection):
        # 获取需要修改的值
        old_value = document.get(field)
        # 如果值不存在，则跳过此文档
        if not old_value:
            continue
        # 添加到 bulk 操作列表中
        bulk_operations.append(
            UpdateOne(
                {"_id": document["_id"]},
                {"$set": {field: []}}
            )
        )

        print(f"已修改 {old_value} 为 [ ] ")

    # 如果有需要更新的文档，则执行 bulk 操作
    if bulk_operations:
        collection.bulk_write(bulk_operations)



def main():
    # 连接数据库，定义基础信息
    client = MongoClient('mongodb://admin:devops@192.168.1.100:27017/')
    db = client['database']
    collection = db['dr.users']
    # 字段名
    field = "qualificationsPics"

    # 需要哪个则去掉哪个的注释
    # 随机中文名
    #update_chinese_name(collection, field)
    # 后5位随机数
    #update_number(collection, field)
    # 多层嵌套后5位随机数
    #update_number_in(collection, field)
    # 清空，改为 null
    #update_none(collection, field)
    # 后5位随机大小写数字
    #update_token_in(collection, field)
    # 设为空数组
    update_none_list(collection, field)


if __name__ == '__main__':
    main()
